#pragma once

#include <string>
#include <stdexcept>

namespace CFileLib
{
	class OpenFileFail : public std::runtime_error
	{
	public:
		inline OpenFileFail(const std::string& what) noexcept :
			std::runtime_error(what)
		{
		}
	};

	class ReadFileFail : public std::runtime_error
	{
	public:
		inline ReadFileFail(const std::string& what) noexcept :
			std::runtime_error(what)
		{
		}
	};

	class WriteFileFail : public std::runtime_error
	{
	public:
		inline WriteFileFail(const std::string& what) noexcept :
			std::runtime_error(what)
		{
		}
	};

	class CFile
	{
	public:
		enum class Mode
		{
			Unknown,
			ReadOnly,
			WriteOnly,
			Append
		};

	protected:
		std::string path;
		void* fp;
		Mode mode;
		bool binary;
		bool opened;

		void Open();

	public:
		void Open(const std::string& f, bool is_binary, Mode openmode);
		void Close();
		CFile();
		CFile(const CFile& f);
		CFile(const std::string& f, bool binary, Mode mode);
		~CFile();

		inline bool IsBinary() const { return binary; }
		inline bool IsOpened() const { return opened; }
		inline Mode GetMode() const { return mode; }
		inline const std::string& GetPath() const { return path; }

		void Read(void* buf, size_t read_size);
		void Write(void* buf, size_t read_size);

		void fgets(char* buf, int bufsize);
		bool fputs(const char* buf);
		bool fputs(const std::string& s);
		bool feof();

		template<typename ReadType> inline void Read(ReadType& r) { Read(&r, sizeof r); }
		template<typename WriteType> inline void Write(WriteType& r) { Write(&r, sizeof r); }
	};
}

